import { u8, u16, u32, u64, i64 } from '../types';

// ELF文件格式常量定义
export const EI_MAG0 = 0;
export const EI_MAG1 = 1;
export const EI_MAG2 = 2;
export const EI_MAG3 = 3;
export const EI_NIDENT = 16;

export const ELFMAG = '\u007fELF';
export const ELFMAG0 = 0x7f;
export const ELFMAG1 = 'E'.charCodeAt(0);
export const ELFMAG2 = 'L'.charCodeAt(0);
export const ELFMAG3 = 'F'.charCodeAt(0);
export const SELFMAG = 4;

export const EI_CLASS = 4;
export const ELFCLASSNONE = 0;
export const ELFCLASS32 = 1;
export const ELFCLASS64 = 2;
export const ELFCLASSNUM = 3;

export const EI_DATA = 5;
export const ELFDATANONE = 0;
export const ELFDATA2LSB = 1;
export const ELFDATA2MSB = 2;
export const ELFDATANUM = 3;

export const EI_VERSION = 6;

export const EI_OSABI = 7;
export const ELFOSABI_NONE = 0;
export const ELFOSABI_SYSV = 0;
export const ELFOSABI_HPUX = 1;
export const ELFOSABI_NETBSD = 2;
export const ELFOSABI_LINUX = 3;
export const ELFOSABI_GNU = 3;
export const ELFOSABI_SOLARIS = 6;
export const ELFOSABI_AIX = 7;
export const ELFOSABI_IRIX = 8;
export const ELFOSABI_FREEBSD = 9;
export const ELFOSABI_TRU64 = 10;
export const ELFOSABI_MODESTO = 11;
export const ELFOSABI_OPENBSD = 12;
export const ELFOSABI_ARM = 97;
export const ELFOSABI_STANDALONE = 255;

export const EI_ABIVERSION = 8;

export const EI_PAD = 9;

export const ET_NONE = 0;
export const ET_REL = 1;
export const ET_EXEC = 2;
export const ET_DYN = 3;
export const ET_CORE = 4;
export const ET_NUM = 5;
export const ET_LOOS = 0xfe00;
export const ET_HIOS = 0xfeff;
export const ET_LOPROC = 0xff00;
export const ET_HIPROC = 0xffff;

export const EM_NONE = 0;
export const EM_M32 = 1;
export const EM_386 = 3;
export const EM_S390 = 22;
export const EM_ARM = 40;
export const EM_NEXGEN32E = 62;
export const EM_X86_64 = EM_NEXGEN32E;
export const EM_IA32E = EM_NEXGEN32E;
export const EM_AMD64 = EM_NEXGEN32E;
export const EM_PDP11 = 65;
export const EM_AARCH64 = 183;

export const GRP_COMDAT = 0x1;
export const STN_UNDEF = 0;

export const EV_NONE = 0;
export const EV_CURRENT = 1;
export const EV_NUM = 2;

export const PT_NULL = 0;
export const PT_LOAD = 1;
export const PT_DYNAMIC = 2;
export const PT_INTERP = 3;
export const PT_NOTE = 4;
export const PT_SHLIB = 5;
export const PT_PHDR = 6;
export const PT_TLS = 7;
export const PT_NUM = 8;
export const PT_LOOS = 0x60000000;
export const PT_GNU_EH_FRAME = 0x6474e550;
export const PT_GNU_STACK = 0x6474e551;
export const PT_GNU_RELRO = 0x6474e552;

export const PN_XNUM = 0xffff;

export const PF_X = 1;
export const PF_W = 2;
export const PF_R = 4;
export const PF_MASKOS = 0x0ff00000;
export const PF_MASKPROC = 0xf0000000;

export const R_X86_64_NONE = 0;
export const R_X86_64_64 = 1;
export const R_X86_64_PC32 = 2;
export const R_X86_64_GOT32 = 3;
export const R_X86_64_PLT32 = 4;
export const R_X86_64_COPY = 5;
export const R_X86_64_GLOB_DAT = 6;
export const R_X86_64_JUMP_SLOT = 7;
export const R_X86_64_RELATIVE = 8;
export const R_X86_64_GOTPCREL = 9;
export const R_X86_64_32 = 10;
export const R_X86_64_32S = 11;
export const R_X86_64_16 = 12;
export const R_X86_64_PC16 = 13;
export const R_X86_64_8 = 14;
export const R_X86_64_PC8 = 15;

export const STB_LOCAL = 0;
export const STB_GLOBAL = 1;
export const STB_WEAK = 2;
export const STB_NUM = 3;

export const STT_NOTYPE = 0;
export const STT_OBJECT = 1;
export const STT_FUNC = 2;
export const STT_SECTION = 3;
export const STT_FILE = 4;
export const STT_COMMON = 5;
export const STT_TLS = 6;
export const STT_NUM = 7;

export const STV_DEFAULT = 0;
export const STV_INTERNAL = 1;
export const STV_HIDDEN = 2;
export const STV_PROTECTED = 3;

export const SHN_UNDEF = 0;
export const SHN_LORESERVE = 0xff00;
export const SHN_HIRESERVE = 0xffff;
export const SHN_ABS = 0xfff1;
export const SHN_COMMON = 0xfff2;

export const SHF_WRITE = (1 << 0);
export const SHF_ALLOC = (1 << 1);
export const SHF_EXECINSTR = (1 << 2);

export const SHT_NULL = 0;
export const SHT_PROGBITS = 1;
export const SHT_SYMTAB = 2;
export const SHT_STRTAB = 3;
export const SHT_RELA = 4;
export const SHT_HASH = 5;
export const SHT_DYNAMIC = 6;
export const SHT_NOTE = 7;
export const SHT_NOBITS = 8;
export const SHT_REL = 9;
export const SHT_SHLIB = 10;
export const SHT_DYNSYM = 11;

export const DT_NULL = 0;
export const DT_NEEDED = 1;
export const DT_PLTRELSZ = 2;
export const DT_PLTGOT = 3;
export const DT_HASH = 4;
export const DT_STRTAB = 5;
export const DT_SYMTAB = 6;
export const DT_RELA = 7;
export const DT_RELASZ = 8;
export const DT_RELAENT = 9;
export const DT_STRSZ = 10;
export const DT_SYMENT = 11;
export const DT_INIT = 12;
export const DT_FINI = 13;
export const DT_SONAME = 14;
export const DT_RPATH = 15;
export const DT_SYMBOLIC = 16;
export const DT_REL = 17;
export const DT_RELSZ = 18;
export const DT_RELENT = 19;
export const DT_PLTREL = 20;
export const DT_DEBUG = 21;
export const DT_TEXTREL = 22;
export const DT_JMPREL = 23;
export const DT_BIND_NOW = 24;
export const DT_INIT_ARRAY = 25;
export const DT_FINI_ARRAY = 26;
export const DT_INIT_ARRAYSZ = 27;
export const DT_FINI_ARRAYSZ = 28;
export const DT_RUNPATH = 29;
export const DT_FLAGS = 30;

// ELF结构体定义

export class Elf64_Ehdr {
  ident: u8[] = new Array(EI_NIDENT).fill(0);
  type: u16 = 0;
  machine: u16 = 0;
  version: u32 = 0;
  entry: u64 = 0n;
  phoff: u64 = 0n;
  shoff: u64 = 0n;
  flags: u32 = 0;
  ehsize: u16 = 0;
  phentsize: u16 = 0;
  phnum: u16 = 0;
  shentsize: u16 = 0;
  shnum: u16 = 0;
  shstrndx: u16 = 0;
}

export class Elf64_Phdr {
  type: u32 = 0;
  flags: u32 = 0;
  offset: u64 = 0n;
  vaddr: u64 = 0n;
  paddr: u64 = 0n;
  filesz: u64 = 0n;
  memsz: u64 = 0n;
  align: u64 = 0n;
}

export class Elf64_Shdr {
  name: u32 = 0;
  type: u32 = 0;
  flags: u64 = 0n;
  addr: u64 = 0n;
  offset: u64 = 0n;
  size: u64 = 0n;
  link: u32 = 0;
  info: u32 = 0;
  addralign: u64 = 0n;
  entsize: u64 = 0n;
}

export class Elf64_Rel {
  offset: u64 = 0n;
  info: u64 = 0n;
}

export class Elf64_Rela {
  offset: u64 = 0n;
  info: u64 = 0n;
  addend: i64 = 0n;
}

export class Elf64_Sym {
  name: u32 = 0;
  info: u8 = 0;
  other: u8 = 0;
  shndx: u16 = 0;
  value: u64 = 0n;
  size: u64 = 0n;
}

export class Elf64_Dyn {
  tag: i64 = 0n;
  val: u64 = 0n;
}

// ELF相关的工具函数
export function ELF64_ST_BIND(val: u8): u8 {
  return (val >> 4);
}

export function ELF64_ST_TYPE(val: u8): u8 {
  return (val & 0xf);
}

export function ELF64_ST_INFO(bind: u8, type: u8): u8 {
  return ((bind << 4) + (type & 0xf));
}

export function ELF64_R_SYM(i: u64): u64 {
  return (i >> 32n);
}

export function ELF64_R_TYPE(i: u64): u64 {
  return (i & 0xffffffffn);
}

export function ELF64_R_INFO(sym: u64, type: u64): u64 {
  return (((sym) << 32n) + type);
}